#ifndef AER_DEFS_HPP_
#define AER_DEFS_HPP_

#include <cassert>


// Macros ~ ° ~ ~ ° ~ ~ ° ~ ~ ° ~ ~ ° ~ ~ ° ~ ~ ° ~ ~ ° ~ ~ ° ~ ~ ° ~ ~ ° ~ ~ ° 

// ===========================
// + Defines the building OS +
// ===========================
#if defined(__APPLE__) || defined(MACOSX)
#   define AER_MACOS
#elif defined(_WIN32)
#   define AER_WINDOWS
#else
#   define AER_LINUX
#endif

// ==========================
// + Size of memory address +
// ==========================
#if defined(_M_X64) || defined(_LP64)
#   define AER_64            1
#else
#   define AER_64            0
#endif

// ================================================
// + Delete an object and reset its value to null +
// ================================================
#ifndef AER_SAFE_FREE
#   define AER_SAFE_FREE(x)     if (x) {free(x); x = 0;}
#endif

#ifndef AER_SAFE_DELETE
#   define AER_SAFE_DELETE(x)   if (x) {delete x; x = 0;}
#endif

#ifndef AER_SAFE_DELETEV
#   define AER_SAFE_DELETEV(x)  if (x) {delete [] x; x = 0;}
#endif

// ==============================================
// + Transform a set of character as a C string +
// ==============================================
#ifndef AER_STRINGIFY
#   define AER_STRINGIFY(x)     (#x)
#endif

// ====================
// + Custom assertion +
// ====================
#ifndef AER_ASSERT
#   define AER_ASSERT(x)        assert(x)
#endif

// ==================
// + Checking macro +
// ==================
#ifndef AER_CHECK
# ifdef NDEBUG
#   define AER_CHECK(x)         (x)
# else
#   define AER_CHECK(x)         if (!(x)) {fprintf(stderr,"%s (%d) : \x1b[1;31m %s failed.\x1b[0m\n", __FILE__, __LINE__, #x);}
# endif
#endif

// ============================
// + Defines the null pointer +
// ============================
#ifndef NULLPTR
#   define NULLPTR              (0u)
#endif

//template<typename T> T* NullPtr() { return static_cast<T*>(0); }

#ifndef AER_MEGABYTE
#   define AER_MEGABYTE         (1u<<20)
#endif

#ifndef AER_ARRAYSIZE
#   define AER_ARRAYSIZE(v)     (sizeof(v)/sizeof(v[0]))
#endif

// ================================================================
// + Disallow the copy constructor and operator= functions        +
// + This should be used in the private: declarations for a class +
// ================================================================
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
  TypeName(const TypeName&);               \
  void operator=(const TypeName&)



// Types ~ ° ~ ~ ° ~ ~ ° ~ ~ ° ~ ~ ° ~ ~ ° ~ ~ ° ~ ~ ° ~ ~ ° ~ ~ ° ~ ~ ° ~ ~ ° ~

#include <stdint.h>

namespace aer {

typedef uint8_t   U8;
typedef int8_t    I8;
typedef uint16_t  U16;
typedef int16_t   I16;
typedef uint32_t  U32;
typedef int32_t   I32;
typedef uint64_t  U64;
typedef int64_t   I64;

// at least 32-bit but could be more
typedef uint_fast32_t  U32F;
typedef int_fast32_t   I32F;

// pointers type
#if AER_64
typedef U64   UPTR;
typedef I64   SPTR;
#else
typedef U32   UPTR;
typedef I32   SPTR;
#endif

typedef float   F32;
typedef double  F64;

typedef unsigned char  uchar;
typedef unsigned short ushort;
typedef unsigned int   uint;
typedef unsigned long  ulong;
}



// Algebra types  ~ ° ~ ~ ° ~ ~ ° ~ ~ ° ~ ~ ° ~ ~ ° ~ ~ ° ~ ~ ° ~ ~ ° ~ ~ ° ~

#define GLM_SWIZZLE
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>

namespace aer {

typedef glm::vec2   Vector2;
typedef glm::ivec2  Vector2i;
typedef glm::vec3   Vector3;
typedef glm::ivec3  Vector3i;
typedef glm::vec4   Vector4;
typedef glm::mat3   Matrix3x3;
typedef glm::mat4   Matrix4x4;
typedef glm::mat4x3 Matrix4x3;

typedef glm::quat   Quaternion; // tmp
}


#endif // AER_DEFS_HPP_
